//***************************************************************************//
//*
//* 内容摘要：SDK对外主动接口类
//*	
//* 当前版本：V1.0		
//* 作    者：zhfayuan
//* 完成日期：2017-11-22
//**************************************************************************//
#if !defined(SDMEDIA_H)
#define SDMEDIA_H

#include "SDCommon.h"
#include "SDThread.h"
#include "SDLog.h"
#include "SDMutex.h"
#include "SDClientCommon.h"
#include "SDTermCommon.h"
#include "SDMediaIFace.h"
#include "SDPrivTsMuxer.h"


//¹¤×÷ÓÚ¼¯ÈºÄ£Ê½»¹ÊÇ·Ç¼¯ÈºÄ£Ê½
#define WORK_IN_CLUSTER_MODE					0

//是否支持掉线自动重连
#define SUPPORT_AUTO_RECONNECT					0

class CSDMedia;

//任务结构体
typedef struct _MediaTermTask
{
    int	        nPackType;		//包类型：正常任务包、结束包	
    UINT64      unRoomId;
    UINT64      unSrcUid;
    UINT        unVkekToken;
    BYTE        byIndex;
} MediaTermTask;

//任务结构体
typedef struct _MediaTransTask
{
    int	        nPackType;		//包类型：正常任务包、结束包	
	BYTE        bySrcPath[256];
	BYTE        byDstPath[256];
}MediaTransTask;

typedef struct _DecKeyPair
{
    UINT64 unRoomId;
    UINT64 unSrcUid;
    UINT   unVkekToken;
    BYTE   byIndex;
	BYTE   byVek[VEK_LEN];
}MediaDecKeyPair;

class CSDMediaAvCommon:public CAVProcess
{
    protected:
        UINT64 m_unRoomId;
        CSDMedia* m_pTerm;
    protected:
		BOOL	m_bSeenSps;
		FILE    *m_OutFile;
	    UINT	m_unPacketsBeforeSps;
    protected:
        UINT	m_unJitterBuffDelay;
        FEC_REDUN_METHOD_TYPE m_eRedunMethod;
        UINT	m_unRedunRatio;
        UINT    m_unFecGroupSize;
    public:
        CSDMediaAvCommon(CSDMedia*pCSDMedia,UINT64 unRoomId,BYTE byUserType,BOOL bUseInternalTimestamp);
        virtual ~CSDMediaAvCommon();
    public:
        void SetTransParams(UINT unJitterBuffDelay, FEC_REDUN_METHOD_TYPE eRedunMethod, UINT unRedunRatio, UINT unFecGroupSize, BOOL bEnableNack);
    public:
        //底层视频音频码流输出接口
        void OnRecvVideoStreamData(BYTE byCodec,BYTE byIndex, BYTE* data, UINT nLen, UINT unPTS, BOOL bComplete, BOOL bPrevTotalFrameLost,bool& bLostInGop);
        void OnRecvAudioStreamData(BYTE byCodec,BYTE byIndex, BYTE* data, UINT nLen, UINT unPts);
        void OnCheckedTokenUpdate(UINT64 unSrcUid,UINT unVkekToken,BYTE byIndex,BYTE byCrypto);

        //父类虚函数的实现
        UINT64 GetAudioDownChannelsMask();
        UINT64 GetVideoDownChannelsMask();
};

//SDK接口类
class  CSDMedia : public CSDMessage, public CSDSingleComSocket
{
public:

    DLLEXPORT CSDMedia(CSDMediaIFace* pCltIFace,UINT LoginCode, BYTE byTermType = TERM_TYPE_PC_W, BOOL bUseInternalTimestamp = TRUE);
    DLLEXPORT virtual ~CSDMedia();

    BOOL m_bUseInternalTimestamp;
public: 
    //私有文件格式提取
    DLLEXPORT int IFace_Extract(std::string strSrcPath,std::string strDstPath);
    DLLEXPORT int IFace_ExtractAv(std::string strSrcPath,std::string strDstPath);
    //普通文件转码成私有文件
    DLLEXPORT int IFace_Compress(std::string strSrcPath,std::string strDstPath,UINT64 unUid,UINT unVekToken=0,BYTE* byVkek=NULL,UINT unVkekLen=0);
public: 
    //文件录像接口
    //关闭私有文件Muxer
    DLLEXPORT void IFace_ClosePrivMuxer();
    //创建私有文件Muxer
    DLLEXPORT void IFace_CreatePrivMuxer(std::string strPath,UINT64 unUid,BYTE byAudioCodec,BYTE byVideoCodec,UINT unVekToken,BYTE*byVkek,UINT unVkekLen,BOOL bEnSecure);
    //私有文件写视频流
    DLLEXPORT void IFace_WriteVideoData(BYTE byCodec,BYTE byIsKey,BYTE* buf, UINT unLen, UINT unDts = 0);
    //私有文件写音频流
    DLLEXPORT void IFace_WriteAudioData(BYTE byCodec,BYTE* buf, UINT unLen, UINT unDts = 0);
    //获取私有文件时长
    DLLEXPORT int IFace_GetFileDuration(std::string strSrcPath);
public: 
	// 登录服务器
    DLLEXPORT int IFace_Online(const char* strIp,UINT nPort,BYTE byUserType,UINT64 unUid, BYTE byNetType = OPERATOR_OTHER);

	// 从服务器下线
    DLLEXPORT void IFace_Offline();

	// 请求上传AV到指定位置【Online成功后调用】
    DLLEXPORT int IFace_OnPosition(UINT64 unRoomId,BYTE byUserType,BYTE byVideoCodec,BYTE byAudioCodec,BYTE byRecvWhenError,BYTE byEmergency,UINT unVekToken,BYTE* byVkek,UINT64 unVkekLen,BOOL bEnSecure);

	// 请求上传AV到指定位置【Online成功后调用】
    DLLEXPORT int IFace_GetPosition(UINT64 unRoomId);

	// 请求从指定位置下来【Online成功后调用】
    DLLEXPORT void IFace_OffPosition(UINT64 unRoomId);

	// 发送已编码的一帧视频码流，内部自带拆分功能【必须传入带起始码的码流】
    DLLEXPORT void IFace_SendVideoStreamData(UINT64 unRoomId,BYTE byCodec,BYTE byIsKey,BYTE* buf, UINT unLen, UINT unDts = 0);

	// 发送已编码的一帧音频码流【建议输入ADTS流以支持服务器TS录制和RTMP旁路直播功能】
    DLLEXPORT void IFace_SendAudioStreamData(UINT64 unRoomId,BYTE byCodec,BYTE* buf, UINT unLen, UINT unDts = 0);

	// 使用掩码方式设置本客户端接收哪几路音视频【Online之前或者之后均可调用】
    DLLEXPORT BOOL IFace_SetAvDownMasks (UINT64 unRoomId,UINT64 unAudioMask, UINT64 unVideoMask);

	//设置传输参数，若不调用本API将使用默认传输参数【必须Online之前调用】
    DLLEXPORT void IFace_SetTransParams(UINT unJitterBuffDelay, FEC_REDUN_METHOD_TYPE eRedunMethod, UINT unRedunRatio, UINT unFecGroupSize, BOOL bEnableNack);

	//获得音视频上下行丢包率
    DLLEXPORT void IFace_GetVideoAudioUpDownLostRatio(UINT64 unRoomId,float &fVideoUpLostRatio, float &fVideoDownLostRatio,
											float &fAudioUpLostRatio, float &fAudioDownLostRatio);
	//获得视频通道上当前的RTT
    DLLEXPORT UINT IFace_GetNetWorkDelayOnVideoChannel(UINT64 unRoomId);

	//获得音视频上下行码率
    DLLEXPORT void IFace_GetVideoAudioUpDownBitrate(UINT64 unRoomId,float &fVideoUpRate, float &fVideoDownRate, float &fAudioUpRate, float &fAudioDownRate);

	//获得当前P2P工作状态[本API对于非P2P版本无效，仅用于保持接口统一]
	E_P2P_Status IFace_GetP2PWorkStatus();

	//启用或者关闭P2P功能,默认不调用的话为启用[本API对于非P2P版本无效，仅用于保持接口统一]
	void IFace_EnableP2P(BOOL bEnableP2P);
	
	//设置本地视频发送帧率，从而启用本地发送Smooth处理功能注意该帧率要符合实际帧率,可以高于实际帧率，
	//但不能低于实际帧率，否则将导致发送速度不足。不调用本函数时，默认关闭smooth处理
	void IFace_SetVideoFrameRateForSmoother(UINT unFrameRate);

    DLLEXPORT BOOL IsVideoFile(std::string path);
	//获得当前的版本号
    DLLEXPORT UINT IFace_GetVersion();
public:
	BOOL ForceSendLost(UINT64 unRoomId,LOST_METHOD_TYPE eLostMethod, UINT unLostValue, UINT unPacketsLostContinue = 1);
public:

	void OnRecvVideoStreamData(UINT64 unRoomId,BYTE byCodec,BYTE byIndex, BYTE* data, UINT nLen, UINT unPTS,VideoFrameInfo info);
	void OnRecvAudioStreamData(UINT64 unRoomId,BYTE byCodec,BYTE byIndex, BYTE* data, UINT nLen, UINT unPts,AudioFrameInfo info);
    void OnCheckedTokenUpdate(UINT64 unSrcUid,UINT64 unRoomId,UINT unVkekToken,BYTE byIndex,BYTE byCrypto);

	UINT64 GetAudioDownChannelsMask(UINT64 unRoomId);
	UINT64 GetVideoDownChannelsMask(UINT64 unRoomId);


private:

	//底层TCP链接的一些错误处理
	void Error(int nErrorId);
	void SetRoomAudioDownChannelsMask(UINT64 unRoomId,UINT64 unAudioMask);
	void SetRoomVideoDownChannelsMask(UINT64 unRoomId,UINT64 unVideoMask);

	void Command(PACK_MESSAGE* pack);
	int  ProcessMessage(void* pParam);
	BOOL RespondPackMessage(PACK_MESSAGE *pack)
	{
		CSDSingleComSocket::UpdateSynRetBuf(pack);
		return TRUE;
	}

private:
	BOOL mfIsWork() { return CSDSingleComSocket::IsWork() && m_bOnlineStatus; };
	BOOL mfInit();
	void mfClose(BOOL bCloseHandThread,BOOL bCloseMessageThread = TRUE, BOOL bCloseTcpThread = TRUE, BOOL bCloseAvProcess = TRUE,BOOL bCloseAuthThread=TRUE);

	BOOL mfConnect(char* strIp, int nPortId, int nPingPort);
	int  mfProcessBroadcast(PACK_MESSAGE* pack);
	BOOL mfSendCmd1(USHORT shCmdMessage);
	BOOL mfSendCmd2(USHORT shCmdMessage, UINT64 unSrcUid, UINT64 unDesUid,UINT64 unOther1 = 0, UINT64 unOther2 = 0);
	
	int  mfGetDecKey(UINT64 unSrcUid,UINT64 unRoomId,BYTE byIndex,UINT unVkekToken,BYTE byVkek[PK_LEN]);

	int  mfOnLine(UINT64 unUid,BYTE byUserType, BYTE byNetType);
	void mfOffLine();

	int  mfConnectMsgServer(UINT64 unUid,BYTE byNetType);


	void mfHandleMessage(PACK_MESSAGE *pack);
	static int IsTerminalCloseRequest(void* pParam);

private:
	void Extra2ZipFile(std::string src,std::string dst,std::string name);
	bool CalCrcForZip(std::string path, unsigned long* result_crc);

private:
    void PrintHex(BYTE *pre, BYTE*by, UINT unLen);
    void MyPubKeyExchangeSerRandom(UINT &uSendInterval,UINT &unState,SM_RANDOM &stRandom);
    void MyRandomExchangeSerPubKey(UINT &uSendInterval,UINT &unState,SM_RANDOM &stRandom);
    void MyEmptyExchangeSerRandom(UINT &uSendInterval,UINT &unState,SM_RANDOM &stRandom);
    void MyCompositeRandomExchangeVkek(UINT &uSendInterval,UINT &unState,SM_RANDOM &stRandom);


	void PutTsVideo(void* pTsMuxer, BYTE *data, UINT nLen, BYTE byCodec,bool bPacketLost, bool bTotalFrameLost, UINT nCurrTimestamp, bool& nWaitIdr);
	void PutTsAudio(void* pTsMuxer, BYTE *data, UINT nLen, BYTE byCodec,UINT nCurrTimestamp, bool& nWaitIdr);
private:	
    void TaskThread();
    void ExtractThread();
private:	
	//TCP心跳线程
	static int HandleThread(void* pParam);
	static int HandleThreadClose(void* pParam);

    //加密认证线程
    static int AuthThread(void* pParam);
    static int AuthThreadClose(void* pParam);

    //转码线程
    static int ExtractThreadProc(void* pParam);
    static int ExtractThreadProcClose(void* pParam);

    static int TaskThreadProc(void* pParam);
    static int TaskThreadProcClose(void* pParam);
    static int SDEnum(struct stIdentity& identity);
private:
    CSDThread           m_AuthThread;
    CSDEvent            m_AuthRetryEvent;
private:
    CSDThread           m_ExtractThread;
	bool	    	    m_bExtractThreadIsCreate;
    DualQueId           m_ExtractThreadTaskQue;
    BOOL		        m_bExtractThreadExit;
private:
    map<UINT64,CSDMediaAvCommon*> m_nRoomAvCommon;
private:
	CSDMediaIFace*	    m_pCltIFace;
	BOOL				m_bNoblockRequest;

    SM2_KEY_PAIR        m_stKeyPair;
    BYTE                m_byVek[VEK_LEN];

	char				m_strDomainSerIp[128];
    UINT                m_unSerPort;
    UINT                m_nConnectSerIp;

    UINT64              m_unUid;

    BYTE                m_unSeq;
	BYTE				m_byTermType;
    //上线状态标记
	volatile BOOL				m_bOnlineStatus;
    //秘钥是否已经协商成功
	volatile BOOL				m_bKeyNegotiated;
    //私有格式Muxer,支持加密
    CPrivTsMuxer        m_PrivTsMuxer;
	//资源是否回收
	BOOL				m_bCloseFlag;
	//是否已经通知外层底层连接错误，该标志用于避免多次通知的情况
	BOOL				m_bNotifyError;	
	
	//底层连接错误原因
	UINT				m_unErrorReason;	

	void*				m_execs;
	void*				m_cmdRecvCs;
    void*               m_avCs;


	//要发出的通用请求包,构造时分配内存
	PACK_MESSAGE*		m_packRequest;		

	//用于给当前服务器发送周期性心跳包的线程
	CSDThread			m_HandleThread;
	CSDEvent			m_HandleEvent;


    map<UINT64,UINT64>    m_unAudioDownChannelsMaskMap;
    map<UINT64,UINT64>    m_unVideoDownChannelsMaskMap;
    map<UINT64,UINT>    m_unAvUpPositionMap;

	bool				m_bTcpRecvThreadIsCreate;

    //参数 For AVProcess
    UINT	m_unJitterBuffDelay;
    FEC_REDUN_METHOD_TYPE m_eRedunMethod;
    UINT	m_unRedunRatio;
    UINT    m_unFecGroupSize;
    BOOL    m_bEnableNack;

	//收到当前服务器心跳包的计数，用于判断该客户端是否已经处于无效状态
	UINT				m_unCurrHandPacketCount;

	//标识本次主动登录（不包括内部掉线重连，内部重连使用不变的唯一登录码）的唯一登录码
	UINT				m_unLogonCode;	

public:
    BOOL		    m_bTaskThreadExit;
    // 线程任务队列，线程池中每个线程都有一个用于接受任务的队列
    CSDThread       m_TaskThread;
    DualQueId       m_TaskThreadTaskQue;
	bool	    	m_bTaskThreadIsCreate;
};
#endif // !defined(SDTERMINAL_H)
